﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;

namespace System.Common.Native
{
  public static class ConsoleManager
  {
    public static bool HasConsole
    {
      get { return Kernel.GetConsoleWindow() != IntPtr.Zero; }
    }

    public static void Show()
    {
      if ( HasConsole )
        return;

      Kernel.AllocConsole();
      InvalidateOutAndError();
    }

    public static void Hide()
    {
      if ( !HasConsole )
        return;

      SetOutAndErrorNull();
      Kernel.FreeConsole();
    }

    private static void InvalidateOutAndError()
    {
      const BindingFlags FLAGS = BindingFlags.Static | BindingFlags.NonPublic;

      var type = typeof( Console );

      var out_field = type.GetField( "_out", FLAGS );
      var error_field = type.GetField( "_error", FLAGS );
      var initialize_std_out_error = type.GetMethod( "InitializeStdOutError", FLAGS );

      Debug.WriteLineIf( out_field == null, "out_field is null" );
      Debug.WriteLineIf( error_field == null, "error_field is null" );
      Debug.WriteLineIf( initialize_std_out_error == null, "error_field is null" );

      if ( out_field == null )
        return;

      out_field.SetValue( null, null );

      if ( error_field == null )
        return;

      error_field.SetValue( null, null );

      if ( initialize_std_out_error != null )
        initialize_std_out_error.Invoke( null, new object[] { true } );
    }

    private static void SetOutAndErrorNull()
    {
      Console.SetOut( TextWriter.Null );
      Console.SetError( TextWriter.Null );
    }
  }
}
